package com.meiyuetao.myt.purchase.service;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import lab.s2jh.auth.entity.Department;
import lab.s2jh.auth.security.AuthUserHolder;
import lab.s2jh.auth.service.DepartmentService;
import lab.s2jh.bpm.service.ActivitiService;
import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.meiyuetao.myt.core.constant.StorageModeEnum;
import com.meiyuetao.myt.core.constant.VoucherStateEnum;
import com.meiyuetao.myt.core.constant.VoucherTypeEnum;
import com.meiyuetao.myt.core.service.VoucherNumGenerateService;
import com.meiyuetao.myt.finance.dao.AccountSubjectDao;
import com.meiyuetao.myt.finance.dao.BizTradeUnitDao;
import com.meiyuetao.myt.finance.dao.TradeReceiptDao;
import com.meiyuetao.myt.finance.entity.AccountInOut;
import com.meiyuetao.myt.finance.entity.BizTradeUnit;
import com.meiyuetao.myt.finance.entity.TradeReceipt;
import com.meiyuetao.myt.finance.entity.TradeReceiptDetail;
import com.meiyuetao.myt.finance.service.AccountInOutService;
import com.meiyuetao.myt.finance.service.TradeReceiptService;
import com.meiyuetao.myt.md.entity.Commodity;
import com.meiyuetao.myt.purchase.dao.PurchaseOrderDao;
import com.meiyuetao.myt.purchase.dao.PurchaseOrderDetailDao;
import com.meiyuetao.myt.purchase.dao.PurchaseReceiptDao;
import com.meiyuetao.myt.purchase.entity.PurchaseOrder;
import com.meiyuetao.myt.purchase.entity.PurchaseOrder.PurchaseOrderPayModeEnum;
import com.meiyuetao.myt.purchase.entity.PurchaseOrderDetail;
import com.meiyuetao.myt.purchase.entity.PurchaseReceipt;
import com.meiyuetao.myt.purchase.entity.PurchaseReceiptDetail;
import com.meiyuetao.myt.purchase.entity.Supplier;
import com.meiyuetao.myt.stock.dao.StockInOutDao;
import com.meiyuetao.myt.stock.dao.StorageLocationDao;
import com.meiyuetao.myt.stock.entity.CommodityStock;
import com.meiyuetao.myt.stock.entity.StockInOut;
import com.meiyuetao.myt.stock.entity.StorageLocation;
import com.meiyuetao.myt.stock.service.CommodityStockService;
import com.meiyuetao.myt.stock.service.StockInOutService;

@Service
@Transactional
public class PurchaseOrderService extends BaseService<PurchaseOrder, Long> {

    @Autowired
    private AccountInOutService accountInOutService;

    @Autowired
    private PurchaseOrderDao purchaseOrderDao;
    @Autowired
    private PurchaseOrderDetailDao purchaseOrderDetailDao;

    @Autowired
    private BizTradeUnitDao bizTradeUnitDao;

    @Autowired
    private AccountSubjectDao accountSubjectDao;

    @Autowired
    private CommodityStockService commodityStockService;

    @Autowired
    private StockInOutDao stockInOutDao;

    @Autowired(required = false)
    private ActivitiService activitiService;

    @Autowired
    private StockInOutService stockInOutService;
    @Autowired
    private VoucherNumGenerateService voucherNumGenerateService;
    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private TradeReceiptDao tradeReceiptDao;
    @Autowired
    private StorageLocationDao storageLocationDao;
    @Autowired
    private TradeReceiptService tradeReceiptService;
    @Autowired
    private PurchaseReceiptService purchaseReceiptService;
    @Autowired
    private PurchaseReceiptDao purchaseReceiptDao;

    @Override
    protected BaseDao<PurchaseOrder, Long> getEntityDao() {
        return purchaseOrderDao;
    }

    public void bpmCreate(PurchaseOrder entity, Map<String, Object> variables) {
        this.save(entity);
        activitiService.startProcessInstanceByKey("BPM_PURCHASE_ORDER", entity);
    }

    public void bpmUpdate(PurchaseOrder entity, String taskId, Map<String, Object> variables) {
        this.save(entity);
        activitiService.completeTask(taskId, variables);
    }

    private AccountInOut buildDefaultAccountInOut(PurchaseOrder entity) {
        AccountInOut accountInOut = new AccountInOut();
        accountInOut.setVoucher(entity.getVoucher());
        accountInOut.setVoucherType(VoucherTypeEnum.JHD);
        accountInOut.setPostingDate(entity.getVoucherDate());
        return accountInOut;
    }

    public void bpmPay(PurchaseOrder entity, String taskId, List<TradeReceiptDetail> tradeReceiptDetails) {
        Supplier supplier = entity.getSupplier();
        // 创建付款单
        TradeReceipt tradeReceipt = new TradeReceipt();
        tradeReceipt.setVoucher(voucherNumGenerateService.getVoucherNumByType(VoucherTypeEnum.FKD));
        tradeReceipt.setVoucherDate(new Date());
        tradeReceipt.setVoucherUser(AuthUserHolder.getLogonUser());
        Department department = AuthUserHolder.getLogonUser().getDepartment();
        if (department == null) {
            department = departmentService.findByProperty("code", "MGMT");
        }
        tradeReceipt.setVoucherDepartment(department);
        BizTradeUnit bizTradeUnit = bizTradeUnitDao.findOne(supplier.getBizTradeUnitId());
        tradeReceipt.setBizTradeUnit(bizTradeUnit);
        tradeReceipt.setBizVoucher(entity.getVoucher());
        tradeReceipt.setBizVoucherType(VoucherTypeEnum.JHD);
        tradeReceipt.setReferenceVoucher(entity.getVoucher());
        tradeReceipt.setReceiptType(VoucherTypeEnum.FKD);
        tradeReceipt.setPayTime(new Date());
        tradeReceipt.setVoucherState(VoucherStateEnum.POST);
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
            tradeReceiptDetail.setTradeReceipt(tradeReceipt);
            tradeReceiptDetail.setPayTime(new Date());
            totalAmount = totalAmount.add(tradeReceiptDetail.getAmount());
            tradeReceipt.addTradeReceiptDetail(tradeReceiptDetail);
        }
        tradeReceipt.setTotalAmount(totalAmount);
        tradeReceipt.setAccountSubject(entity.getAccountSubject());
        // tradeReceiptDao.save(tradeReceipt);
        tradeReceiptService.create(tradeReceipt);
        /*
         * List<AccountInOut> accountInOuts = Lists.newArrayList();
         * 
         * //借：1123=预付账款 AccountInOut accountInOut1 =
         * buildDefaultAccountInOut(entity);
         * accountInOut1.setAccountSubject(entity.getAccountSubject());
         * accountInOut1.setAccountSummary("采购订单[" + entity.getVoucher() +
         * "]付款"); accountInOut1.setAmount(entity.getActualPayedAmount());
         * accountInOut1.setAccountDirection(true);
         * accountInOut1.setBizTradeUnit
         * (bizTradeUnitDao.findOne(supplier.getBizTradeUnitId()));
         * accountInOuts.add(accountInOut1); //贷：用户选择结算科目，如1001=库存现金 for
         * (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
         * AccountInOut accountInOut2 = buildDefaultAccountInOut(entity);
         * //AccountSubject accountSubject2 =
         * accountSubjectDao.findOne(tradeReceiptDetail
         * .getAccountSubject().getId());
         * accountInOut2.setAccountSubject(tradeReceiptDetail
         * .getAccountSubject()); accountInOut2.setAccountSummary("采购订单[" +
         * entity.getVoucher() + "]付款");
         * accountInOut2.setAmount(tradeReceiptDetail.getAmount());
         * accountInOut2.setAccountDirection(false);
         * accountInOuts.add(accountInOut2);
         * 
         * }
         * 
         * accountInOutService.saveBalance(accountInOuts);
         */
        // 德国库模式并且后付款自动入库，更新库存信息
        if (StorageModeEnum.AUTO.equals(entity.getStorageMode())) {
            entity = this.autoReceipt(entity);
        }
        bpmUpdate(entity, taskId, null);
    }

    public void bpmDelivery(PurchaseOrder entity, String taskId) {
        List<PurchaseOrderDetail> purchaseOrderDetails = entity.getPurchaseOrderDetails();
        for (PurchaseOrderDetail purchaseOrderDetail : purchaseOrderDetails) {
            Commodity commodity = purchaseOrderDetail.getCommodity();
            StorageLocation storageLocation = purchaseOrderDetail.getStorageLocation();
            CommodityStock commodityStock = commodityStockService.findBy(commodity, storageLocation);
            if (commodityStock == null) {
                commodityStock = new CommodityStock();
                commodityStock.setCommodity(commodity);
                commodityStock.setStorageLocation(storageLocation);
                commodityStock.setCostPrice(purchaseOrderDetail.getPrice());
            }

            StockInOut stockInOut = new StockInOut(entity.getVoucher(), purchaseOrderDetail.getSubVoucher(), VoucherTypeEnum.JHD, commodityStock);
            stockInOut.setDiffPurchasingQuantity(purchaseOrderDetail.getQuantity());
            stockInOut.setOperationSummary("采购订单更新在途库存量");
            stockInOutService.saveCascade(stockInOut);
        }
        bpmUpdate(entity, taskId, null);
    }

    /**
     * 单据红冲
     * 
     * @param entity
     */
    public void redword(PurchaseOrder entity) {
        Assert.isTrue(entity.getRedwordDate() == null);

        // 移除工作流实例
        activitiService.deleteProcessInstanceByEntity(entity);

        entity.setRedwordDate(new Date());
        entity.setLastOperationSummary(entity.buildLastOperationSummary("红冲"));
        purchaseOrderDao.save(entity);

        // 克隆创建红冲对象，只复制主对象，明细行项数据不复制
        PurchaseOrder redwordTarget = new PurchaseOrder();
        String[] copyIgnoreProperties = ArrayUtils.addAll(entity.retriveCommonProperties(), new String[] { "purchaseOrderDetails", "voucher", "voucherDate" });
        BeanUtils.copyProperties(entity, redwordTarget, copyIgnoreProperties);
        redwordTarget.setVoucherDate(new Date());
        redwordTarget.setVoucher("R" + entity.getVoucher());
        purchaseOrderDao.save(redwordTarget);

        // 处理库存红冲退回
        stockInOutService.redword(entity.getVoucher(), VoucherTypeEnum.JHD, redwordTarget.getVoucher());

        // 处理财务红冲退回
        accountInOutService.redword(entity.getVoucher(), VoucherTypeEnum.JHD, redwordTarget.getVoucher());
    }

    @Override
    public void delete(PurchaseOrder entity) {
        activitiService.deleteProcessInstanceByEntity(entity);
        super.delete(entity);
    }

    // 用于自动入库
    public PurchaseOrder autoReceipt(PurchaseOrder bindingEntity) {
        PurchaseReceipt purchaseReceipt = new PurchaseReceipt();
        purchaseReceipt.setVoucher(voucherNumGenerateService.getVoucherNumByType(VoucherTypeEnum.JH));
        purchaseReceipt.setVoucherDate(bindingEntity.getVoucherDate());
        purchaseReceipt.setVoucherUser(bindingEntity.getVoucherUser());
        purchaseReceipt.setVoucherDepartment(bindingEntity.getVoucherDepartment());
        purchaseReceipt.setMemo(bindingEntity.getPurchaseMemo());
        purchaseReceipt.setPurchaseOrder(purchaseOrderDao.findOne(Long.valueOf(bindingEntity.getId())));
        purchaseReceipt.setLogisticsNo(bindingEntity.getLogisticsNo());
        purchaseReceipt.setLogistics(bindingEntity.getLogistics());
        purchaseReceipt.setSupplier(bindingEntity.getSupplier());
        purchaseReceipt.setExternalVoucher(bindingEntity.getVoucher());
        purchaseReceipt.setVoucherState(VoucherStateEnum.POST);
        purchaseReceipt.setTotalCommodityAmount(bindingEntity.getAmount());
        purchaseReceipt.setTotalDeliveryAmount(bindingEntity.getTotalDeliveryAmount());
        purchaseReceipt.setTotalCostAmount(bindingEntity.getTotalAmount());
        purchaseReceipt.setPayedAmount(bindingEntity.getActualPayedAmount());
        // List<PurchaseReceiptDetail> purchaseReceiptDetails = new
        // ArrayList<PurchaseReceiptDetail>();
        purchaseReceiptDao.save(purchaseReceipt);
        List<PurchaseReceiptDetail> purchaseReceiptDetails = purchaseReceipt.getPurchaseReceiptDetails();
        for (PurchaseOrderDetail pod : bindingEntity.getPurchaseOrderDetails()) {

            PurchaseReceiptDetail prd = new PurchaseReceiptDetail();
            prd.setCommodity(pod.getCommodity());
            prd.setSubVoucher(pod.getSubVoucher());
            prd.setQuantity(pod.getQuantity());
            prd.setPrice(pod.getPrice());
            // prd.setPurchaseOrderDetail(pod);
            prd.setPurchaseOrderDetail(purchaseOrderDetailDao.findOne(Long.valueOf(pod.getId())));
            prd.setMeasureUnit(pod.getMeasureUnit());
            prd.setOriginalAmount(pod.getOriginalAmount());
            prd.setDiscountRate(pod.getDiscountRate());
            prd.setDiscountAmount(pod.getDiscountAmount());
            prd.setAmount(pod.getAmount());
            prd.setDeliveryAmount(pod.getDeliveryAmount());
            prd.setStorageLocation(pod.getStorageLocation());

            prd.setCostPrice(pod.getCostPrice());
            prd.setCostAmount(pod.getCostAmount());
            prd.setPurchaseReceipt(purchaseReceipt);
            purchaseReceiptDetails.add(prd);
        }

        purchaseReceipt = purchaseReceiptService.save(purchaseReceipt);
        return purchaseReceipt.getPurchaseOrder();

    }

    public void bpmReceipt(PurchaseOrder bindingEntity, String taskId, Map<String, Object> variables, String allReceipt) {
        PurchaseReceipt purchaseReceipt = new PurchaseReceipt();
        purchaseReceipt.setVoucher(voucherNumGenerateService.getVoucherNumByType(VoucherTypeEnum.JH));
        purchaseReceipt.setVoucherDate(bindingEntity.getVoucherDate());
        purchaseReceipt.setVoucherUser(bindingEntity.getVoucherUser());
        purchaseReceipt.setVoucherDepartment(bindingEntity.getVoucherDepartment());
        purchaseReceipt.setMemo(bindingEntity.getPurchaseMemo());
        PurchaseOrder dbPurchaseOrder = purchaseOrderDao.findOne(Long.valueOf(bindingEntity.getId()));

        purchaseReceipt.setPurchaseOrder(dbPurchaseOrder);
        purchaseReceipt.setLogisticsNo(bindingEntity.getLogisticsNo());
        purchaseReceipt.setLogistics(bindingEntity.getLogistics());
        purchaseReceipt.setSupplier(bindingEntity.getSupplier());
        purchaseReceipt.setExternalVoucher(bindingEntity.getVoucher());
        purchaseReceipt.setVoucherState(VoucherStateEnum.POST);
        purchaseReceipt.setTotalCommodityAmount(bindingEntity.getAmount());
        purchaseReceipt.setTotalDeliveryAmount(bindingEntity.getTotalDeliveryAmount());
        purchaseReceipt.setTotalRoadAmount(new BigDecimal(bindingEntity.getExtraAttributesValue("totalRoadAmount")));
        purchaseReceipt.setTotalCostAmount(new BigDecimal(bindingEntity.getExtraAttributesValue("totalCostAmount")));
        purchaseReceipt.setPayedAmount(bindingEntity.getActualPayedAmount());
        List<PurchaseReceiptDetail> purchaseReceiptDetails = purchaseReceipt.getPurchaseReceiptDetails();
        for (PurchaseOrderDetail pod : bindingEntity.getPurchaseOrderDetails()) {

            PurchaseReceiptDetail prd = new PurchaseReceiptDetail();
            prd.setCommodity(pod.getCommodity());
            prd.setSubVoucher(pod.getSubVoucher());
            prd.setQuantity(pod.getQuantity());
            prd.setPrice(pod.getPrice());
            if (pod.isNew()) {
                prd.setPurchaseOrderDetail(null);

            } else {
                prd.setPurchaseOrderDetail(purchaseOrderDetailDao.findOne(Long.valueOf(pod.getId())));
            }

            prd.setMeasureUnit(pod.getMeasureUnit());
            prd.setOriginalAmount(pod.getOriginalAmount());
            prd.setDiscountRate(pod.getDiscountRate());
            prd.setDiscountAmount(pod.getDiscountAmount());
            prd.setAmount(pod.getAmount());
            prd.setDeliveryAmount(pod.getDeliveryAmount());
            prd.setStorageLocation(pod.getStorageLocation());
            prd.setBatchNo(pod.getExtraAttributesValue("batchNo"));
            String expireDate = pod.getExtraAttributesValue("expireDate");
            if (StringUtils.isNotBlank(expireDate)) {
                DateFormat dd = new SimpleDateFormat("yyyy-MM-dd");
                Date date = null;
                try {
                    date = dd.parse(expireDate);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                prd.setExpireDate(date);
            }
            String roadAmount = pod.getExtraAttributesValue("roadAmount");
            if (StringUtils.isNotBlank(roadAmount)) {
                prd.setRoadAmount(new BigDecimal(roadAmount));
            }
            prd.setCostPrice(pod.getCostPrice());
            prd.setCostAmount(pod.getCostAmount());
            prd.setPurchaseReceipt(purchaseReceipt);
            purchaseReceiptDetails.add(prd);
        }
        if (purchaseReceiptDetails.size() > 0) {
            purchaseReceiptService.save(purchaseReceipt);
            dbPurchaseOrder.setReceiptMemo(dbPurchaseOrder.getReceiptMemo() == null ? "" : dbPurchaseOrder.getReceiptMemo() + purchaseReceipt.getMemo());
            purchaseOrderDao.save(dbPurchaseOrder);
        }
        if (Boolean.valueOf(allReceipt)) {
            activitiService.completeTask(taskId, variables);
        }

    }

    public void bpmLevel1Audit(PurchaseOrder entity, String taskId, Map<String, Object> variables) {
        // 德国库模式自动入库，更新库存信息
        if ((Boolean) variables.get("auditLevel1Pass") && entity.getTotalAmount().floatValue() < 10000 && StorageModeEnum.AUTO.equals(entity.getStorageMode())
                && PurchaseOrderPayModeEnum.POST.equals(entity.getPayMode())) {
            entity = this.autoReceipt(entity);
        }
        this.bpmUpdate(entity, taskId, variables);

    }

    public void bpmLevel2Audit(PurchaseOrder entity, String taskId, Map<String, Object> variables) {
        // 德国库模式并且后付款自动入库，更新库存信息
        if ((Boolean) variables.get("auditLevel2Pass") && entity.getTotalAmount().floatValue() >= 10000 && StorageModeEnum.AUTO.equals(entity.getStorageMode())
                && PurchaseOrderPayModeEnum.POST.equals(entity.getPayMode())) {
            entity = this.autoReceipt(entity);
        }
        this.bpmUpdate(entity, taskId, variables);

    }

}
